import json
import logging
import threading
import time
import requests
from datetime import datetime, timedelta
from mcp_server.dwf_api import DWFConfig, APIType

logger = logging.getLogger(__name__)

class DWFClient:
    """
    DWFClient is a client for calling DWF APIs.
    """
    def __init__(self, dwf_config: DWFConfig):
        self.dwf_config = dwf_config
        self.token = None
        self.token_expires_at = None
        self.lock = threading.RLock()
        self.refresh_thread = None


    def _ensure_valid_token(self):
        """确保token有效，如果过期则刷新"""
        with self.lock:
            if not self.token or self._is_token_expired():
                logger.info("[DWF Client]: Token has expired, refreshing...")
                self._login()

    def _is_token_expired(self) -> bool:
        """检查token是否过期（提前5分钟判断为过期）"""
        if not self.token_expires_at:
            return True
        # 提前5分钟刷新token
        return datetime.now() + timedelta(minutes=5) >= self.token_expires_at


    def _login(self):
        """Login to get token"""
        if not self.dwf_config.username or not self.dwf_config.password:
            raise ValueError("username and password must be provided in dwf config")

        login_url = f"{self.dwf_config.get_base_url(APIType.APP)}/dwf/v1/app/login"
        params = {
            'userName': self.dwf_config.username,
            'password': self.dwf_config.password,
            'isEncrypted': False
        }

        try:
            logger.info(f"[DWF Client] Logging in to {login_url}")
            response = requests.get(login_url, params=params, timeout=30)
            response.raise_for_status()

            # Get token from headers
            response_json = response.json()

            token = response_json.get("data")
            if not token:
                raise Exception("Login failed: Token not found in response data field")

            # Set token expiration time (assume 24 hours validity)
            self.token = token
            self.token_expires_at = datetime.now() + timedelta(hours=24)

            logger.info(f"[DWF Client] Login successful, token expires at {self.token_expires_at}")

        except requests.exceptions.RequestException as e:
            logger.error(f"[DWF Client] Login request failed: {e}")
            raise Exception(f"DWF login failed: {e}")
        except Exception as e:
            logger.error(f"[DWF Client] Error during login process: {e}")
            raise


    def request(self, url, method='POST', headers=None, data=None, params=None, return_json=True):
        self._ensure_valid_token()
        if headers is None:
            headers = {}
        headers.update({
            'Content-Type': 'application/json',
            'Authorization': self.token,
        })

        data = json.dumps(data)
        try:
            logger.info(f'[DWF Client] requesting api: {url}')
            start_time = time.time()
            response = requests.request(
                method=method.upper(),
                url=url,
                headers=headers,
                params=params,
                data=data,
                timeout=120,
            )

            # Log response status
            logger.info(f"[DWF Client] Received response: {response.status_code} in {time.time() - start_time:.2f} seconds")

            # Raise HTTP errors if any
            response.raise_for_status()

            # Return parsed JSON or raw text
            if return_json:
                return response.json()
            return response

        except requests.exceptions.ConnectionError as e:
            logger.error(f"[DWF Client] ConnectionError: {e}")
            raise
        except requests.exceptions.Timeout as e:
            logger.error(f"[DWF Client] Timeout: {e}")
            raise
        except requests.exceptions.RequestException as e:
            logger.error(f"[DWF Client]: HTTP error: {e}")
            raise
        except ValueError as e:
            logger.error(f"[DWF Client]: JSON parsing error: {e}")
            raise
        except Exception as e:
            logger.error(f"[DWF Client]: Unexpected error: {e}")
            raise


if __name__ == '__main__':
    # 示例配置
    config = DWFConfig(
        host="http://172.21.11.79",
        app_port=9090,
        modeler_port=6060,
        username="admin",
        password="123456"
    )

    client = DWFClient(config)
    r = client.request("http://172.21.11.79:9090/dwf/v1/meta/entities/Asset", 'GET')
    print(r)

    url = f"http://172.21.11.79:9090/dwf/v1/omf/entities/Asset/objects"
    r = client.request(url, 'POST', data={
        "condition": "",
         "options": [],
    })
    print(r)
